import { type MemberDistrictsListVoList, type MemberMapContactsVoList } from '@/api/contactsMap/types';
import { DefaultCenterPoint } from '@/hooks/core/useLocation';
import { getCurrentInstance, ref, unref, reactive, nextTick } from 'vue';
import { type Marker, type MarkerClusterCreateEvent, type MarkerLabel, type RegionchangeResult } from '../types/map';
import { forEach } from 'lodash-es';
import type { AsyncOptions } from '@dcloudio/types/uni-app/uni/base/Utils';
import { useAppStoreWithOut } from '@/store/modules/app';
import { isIos } from '@/utils/is';

export interface MarkersRef extends Marker {
  scale?: number
}


const maxReNum = 3
/** 将地图方法转换成Promise风格 */
let promisify = function <T>(func: { (options: T): void }, functionName: string) {

  return (args: T): Promise<any> => {
    return new Promise((resolve, reject) => {
      let reNum = 0
      const op = Object.assign(args as any, {
        success: res => {
          console.log(`${functionName} Success`)
          resolve(res)
        },
        fail: (err: { errMsg: string }) => {
          console.log(`${functionName} Fail`, err.errMsg)
          // reject(err)
          if (reNum < maxReNum) {
            reNum += 1
            if (err.errMsg.includes('error mapid')) {
              setTimeout(() => func(op), 300)
            } else {
              func(op)
            }
          } else {
            console.log(`${functionName} 已超过重试次数`, err.errMsg)
            // resolve(err)
            reject(err)
          }
        },
      } as AsyncOptions)
      func(op)
    })
  }
}


export const defaultScale = {
  start: 16,
  province: 8,
  city: 9,
  maxCity: 13,
  area: 13,
};

export const markerStyle = {
  width: 30,
  height: 34,
};

/**
 * @description 生成普通标点数据
 * @date 14/03/2024
 * @param {{
 *   latitude: number;
 *   longitude: number;
 *   iconPath: string;
 *   id: number;
 *   joinCluster?: boolean
 *   width?: number
 *   height?: number
 *   label?: MarkerLabel
 * }} options
 * @returns {*}  {Marker}
 */
function createComMarkerData(options: {
  latitude: number;
  longitude: number;
  iconPath: string;
  id: number;
  joinCluster?: boolean
  width?: number
  height?: number
  label?: MarkerLabel
}): Marker {
  return {
    latitude: options.latitude,
    longitude: options.longitude,
    iconPath: options.iconPath,
    width: options?.width || markerStyle.width,
    height: options?.height || markerStyle.height,
    id: Number(options.id),
    joinCluster: !!options.joinCluster,
  };
}

interface Options {
  mapId: string
  defaultScale?: number
  /** 地图滑动拦截执行后 */
  regionchangeAfter?: (e: RegionchangeResult) => void
  /** 标点点击后 */
  markertapAfter?: (markerId: number) => void
  /** 点聚合点击后 */
  markerClusterClickAfter?: (e: MarkerClusterCreateEvent) => void
}

export function useContactsMap(options: Options) {
  const { mapId } = options

  const { system } = uni.getDeviceInfo()

  const _this = getCurrentInstance()?.proxy as unknown as WechatMiniprogram.Component.TrivialInstance;
  const mapContext: UniApp.MapContext = uni.createMapContext(mapId, _this);

  const _addMarkers = promisify<UniApp.MapContextAddMarkersOptions>(mapContext.addMarkers, 'addMarkers')
  const _removeMarkers = promisify<UniApp.MapContextRemoveMarkersOptions>(mapContext.removeMarkers, 'removeMarkers')
  const _getScale = promisify<UniApp.MapContextGetScaleOptions>(mapContext.getScale, 'getScale')
  const _includePoints = promisify<UniApp.MapContextIncludePointsOptions>(mapContext.includePoints, 'includePoints')
  const _moveToLocation = promisify<UniApp.MapContextMoveToLocationOptions>(mapContext.moveToLocation, 'moveToLocation')

  const query = uni.createSelectorQuery().in(_this);
  const mapSize = reactive({
    width: 0,
    height: 0
  })
  query
    .select(`#${mapId}`)
    .boundingClientRect((res) => {
      const { width, height } = res as UniApp.NodeInfo;
      mapSize.width = width as number
      mapSize.height = height as number
    })
    .exec();

  mapContext.initMarkerCluster({
    enableDefaultStyle: true,
    gridSize: 60,
    zoomOnClick: true,
  });

  const markersRef = ref<MarkersRef[]>([]);

  const centerLocation = ref({
    latitude: DefaultCenterPoint.latitude,
    longitude: DefaultCenterPoint.longitude,
  });

  /**
   * @description 修改地图中心点
   * @date 15/03/2024
   * @param {{ latitude: number; longitude: number }} location
   */
  function changeMapCenter(location: { latitude: number; longitude: number }) {
    centerLocation.value.latitude = location.latitude;
    centerLocation.value.longitude = location.longitude;
  }


  const mapScale = ref<number>(options.defaultScale || defaultScale.province);
  /**
   * @description 动态修改地图的缩放级别
   * @date 15/03/2024
   * @param {number} scale
   */
  function changeMapScale(scale: number) {
    nextTick(() => {
      const diff = mapScale.value - scale;
      if (Math.sign(diff) === 1) {
        mapScale.value = scale - 0.01;
      } else {
        mapScale.value = scale + 0.01;
      }
    });
  }

  /** 创建Markes */
  async function createMarkers(memberContactsVoList: MemberMapContactsVoList[], iconPath: string): Promise<MarkersRef[]> {
    console.log('createMarkers')
    const markers: MarkersRef[] = []
    markersRef.value = []
    forEach(memberContactsVoList, v => {
      const markerItem = createComMarkerData({
        latitude: Number(v.latitude),
        longitude: Number(v.longitude),
        iconPath,
        id: v.memberLeadingId as number,
        joinCluster: false
      })
      markers.push(markerItem)
    })
    await handleCreatedMarkers(markers)
    return markers
  }

  /** 创建自定义聚合点 */
  async function createClusterMarkers(memberDistrictsListVoList: MemberDistrictsListVoList[], iconPath: string, labelColor: string): Promise<MarkersRef[]> {
    console.log('createClusterMarkers')
    const markers: MarkersRef[] = []
    markersRef.value = []
    forEach(memberDistrictsListVoList, v => {
      const extName = v.extName.length > 4 ? v.extName.substring(0, 2) : v.extName
      const item: Marker = {
        id: Number(v.id),
        latitude: Number(v.latitude),
        longitude: Number(v.longitude),
        width: 80,
        height: 80,
        iconPath,
        joinCluster: false,
        label: {
          content: `${extName}\n${v.num}`,
          fontSize: 12,
          color: labelColor,
          width: 80,
          height: 80,
          textAlign: 'center',
          anchorX: isIos(system) ? 0 : -40,
          anchorY: -80,
        }
      }
      markers.push({ ...item, scale: v.scale })
    })
    await handleCreatedMarkers(markers)
    return markers
  }

  async function handleCreatedMarkers(markers: MarkersRef[]) {
    markersRef.value = [...markers]
    return Promise.resolve(true)
  }

  /**
   * @description 标点点击事件
   * @date 15/03/2024
   * @param {{
   *     detail: {
   *       markerId: number;
   *     };
   *   }} e
   */
  function markertap(e: {
    detail: {
      markerId: number;
    };
  }) {
    console.log('Markertap', e.detail);
    const markerId = e.detail?.markerId;
    if (!markerId) return;
    options.markertapAfter?.(markerId)
  }

  /**
   * @description 缩放视野展示所有经纬度
   * @date 15/03/2024
   * @param {UniApp.MapContextIncludePointsOptions} [options={ points: [] }]
   */
  async function includePoints(options: UniApp.MapContextIncludePointsOptions = { points: [] }) {
    let points = options.points || []
    if (!points.length) {
      points = unref(markersRef).map(v => {
        return {
          latitude: v.latitude, longitude: v.longitude
        }
      })
    }
    if (!points.length) return;
    await _includePoints({
      points,
      padding: [30, 30, 30, 30],
    })
  }

  /**
   * 将地图中心移动到当前定位点，需要配合map组件的show-location使用
   * @param options
   */
  function moveToLocation(options: UniApp.MapContextMoveToLocationOptions) {
    return new Promise(async (resolve, reject) => {
      _moveToLocation(options).then(res => {
        if (isIos(system)) {
          changeMapCenter({ latitude: Number(options?.latitude), longitude: Number(options?.longitude) })
          resolve(res)
          return
        }
        setTimeout(() => {
          changeMapCenter({ latitude: Number(options?.latitude), longitude: Number(options?.longitude) })
          resolve(res)
        }, 300)
      }).catch(err => {
        reject(err)
      })
    })
  }

  /**
   * @description 设置地图中心点偏移
   * @date 13/02/2023
   * @param {UniApp.MapContextSetCenterOffsetOptions} options
   */
  function setCenterOffset(options: UniApp.MapContextSetCenterOffsetOptions) {
    // return mapContext.setCenterOffset?.(options);
  }

  const regionchange = async (e: RegionchangeResult) => {
    if (!e) return
    console.log('Regionchange', e.detail);
    if (
      e.causedBy === 'update' ||
      (e.causedBy as string) === 'upudate' ||
      (e.causedBy as string) === 'udpate'
    ) {
      return;
    }

    options.regionchangeAfter?.(e)
  }

  return {
    markersRef,
    centerLocation,
    mapScale,
    includePoints,
    moveToLocation,
    setCenterOffset,
    changeMapScale,
    changeMapCenter,
    markertap,
    regionchange,
    createClusterMarkers,
    createMarkers,
    _removeMarkers
  };
}
